/** @jsxImportSource @emotion/react */
import React, {
    forwardRef,
    ReactNode,
    useEffect,
    useImperativeHandle, useInsertionEffect,
    useRef,
    useState,
} from "react";
import { createPortal } from "react-dom";
import queryString from "query-string";
// import { Print } from "$/Print";
// export { Print };


/*原版来自 "print-react","1.0.3"包。
* */

const FALLBACK_WIDTH = 800;
const FALLBACK_HEIGHT = 1400;
const MARGIN_TOP_DEFAULT = 120;
const MARGIN_LEFT_DEFAULT = 120;

export const sleep = async (milliseconds: number): Promise<unknown> => {
    return new Promise((resolve) => {
        setTimeout(resolve, milliseconds);
    });
};

interface PrintProps {
    children: ReactNode;
    onOpenPrintDialog?: () => void | Promise<void>;
    onClosePrintDialog?: () => void | Promise<void>;
    printWidth?: number;
    marginTop?: number;
    marginLeft?: number;
    canURLprn?: boolean;
    waitime?: number;       //有些数据多的 较慢
}

//原版本 【问题】打印转换器根本没有弹出openPrintDialog啊，直接是打印了。所以还是没有经过这个<Print >组件前置插入的步骤啊。打印转换器走了老路不会陷入这个逻辑。
/**为整个URL触发打印语境。
 * 为了完全动态内容正常打印而生的： 数据必须加载进来，但是不能动态人工修改和输入没保存后端就打印的。
 * 支持打印转发器用。不需要打印对话框也能够正常对完全动态网页 打印，不会在尾部有空白页或缺少应该打印的页。
 * 设置 canURLprn=true & PRINTpdf=1 后才启动。否则不启用（走的保留旧版本按钮驱动的）
 * @test：没有启动的 简易版原始记录的测试：输出68页 启动后自动调整显示区宽度的 输出69页，针对许多依据测量div宽度来动态布局LineColumn的情况。fl14-1；
 * URL参数： ？ & PRINTwidth=718  约束打印纸张的宽度；
 * 工具条肯定不会打印的，隐藏预定义的工具条： #floormenu 元素ID='floormenu'；
 * 手机上chrome打印可能有些问题；
 * */
export const UrlPrint =({
           children,
           printWidth=718,
           onOpenPrintDialog,
           onClosePrintDialog,
           marginLeft,
           marginTop,
           canURLprn,
           waitime=2000,
            ref,
       }: PrintProps & React.HTMLProps<HTMLDivElement>
   ) => {
    const qs= queryString.parse(window.location.search);
    const atPRINTpdf =qs && !!qs.PRINTpdf;
    const [printDialogOpen, setPrintDialogOpen] = useState(canURLprn&&atPRINTpdf);
    useEffect(() => {
        const afterPrint = async () => {
            if (onClosePrintDialog) {
                await onClosePrintDialog();
            }
            setPrintDialogOpen(false);
        };
        window.addEventListener("afterprint", afterPrint);

        return () => {
            window.removeEventListener("afterprint", afterPrint);
        };
    });

    const [dimensions, setDimensions] = useState<{
        width: number;
        height: number;
    }>();
    //【仅仅是】屏幕显示的 ref ：打印预览这个无效的。
    const elementRef =useRef<HTMLDivElement | null>(null);

    useEffect(() => {
        const width: number = elementRef?.current?.clientWidth!;
        const height: number = elementRef?.current?.clientHeight!;
        if (width && height) {
            setDimensions({ width, height });
        } else {
            setDimensions({ width: FALLBACK_WIDTH, height: FALLBACK_HEIGHT });
        }
    }, []);

    const openPrintDialog = async () => {
        try {
            if (onOpenPrintDialog) {
                await onOpenPrintDialog();
            }
            setPrintDialogOpen(true);
            await sleep(waitime);
            window.print();
        } catch (e) {
            // do nothing
        }
    };

    useImperativeHandle(ref, () => ({
        openPrintDialog,
    } as any));

    const usedMarginTop = marginTop ?? MARGIN_TOP_DEFAULT;
    const usedMarginLeft = marginLeft ?? MARGIN_LEFT_DEFAULT;

    console.log("打印VAL", usedMarginTop + (dimensions?.height ?? 0), dimensions, usedMarginTop, usedMarginLeft,printWidth);

    //【最关键】毛病2- width: printWidth ?? dimensions?.width, 需要自己配置打印纸张的大小A4 A3的宽度的+横屏 竖屏的。
    //打下的打印时刻的render是发生在scout.on('beforeprint', beforePrintHandler)前面了，随后原生打印预览环节仅仅做了复制没有再次render给打印输出的时机。导致没有触发useMedia('print')==true;
    //【毛病3】打印对话框关闭或者输出PDF之后的节点才会进入原先原生浏览器打印的运行过程的，但pdf内容始终没有触发useMedia('print')==true。所以语义混淆了丢失！不被认定为打印语境啊！
    //毛病1：按钮点击触发的话无法保留旧的状态数据或手动输入点击变动的内容！表格等数据初始化？只能加载后端的静态内容。但给URL加上？&PRINTpdf=1刷新后就能约束宽度然后用浏览器打印菜单直接打可以避免该毛病的。
    //【毛病2】width必须事前做设置的数字。
    return !printDialogOpen ? (
                  <div ref={elementRef}>{children}</div>
        ) : (
         <>
            {createPortal(
                <div className="PRINT-URL"
                     style={{
                         width: printWidth,
                         // width: printWidth ?? dimensions?.width,
                         // height: printWidth ? undefined : dimensions?.height,
                         position: "absolute",
                         top: 0,
                         left: 0,
                         // marginTop: usedMarginTop,
                         // marginLeft: usedMarginLeft,
                     }}
                >
                    {children}
                </div> as React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | string | number | bigint | Iterable<React.ReactNode> | React.ReactPortal | boolean,
                document.body
            )}
             <style>
                 {
                   `#floormenu { visibility: hidden !important; }`
                 }
             </style>
        </>
    );
};


interface Props {
    node: ReactNode;
    printWidth?: number;
    marginTop?: number;
    marginLeft?: number;
    canURLprn?: boolean;
    waitime?: number;       //有些数据多的 较慢
}
/**仅仅针对单一个组件的打印； 其它元素需要隐藏掉的 ；表格数据编辑: 不能多個表格追加一起做編輯的。
 * 用了<DdMenu icon替代了<Popover>做菜单后会好点：菜单版面紧凑而且易于扩展。
 * 手机上chrome打印可能有些问题；版本？
 * 【毛病】不支持手动输入数据的立刻打印出来，就只能看到URL mount加载来的数据；还会留有许多空白页只有最前面才有内容的。
 * */
export function useDomPrinter({ node, canURLprn, waitime=500, marginTop, marginLeft, printWidth,}
                                      : Props
) {
    const qs= queryString.parse(window.location.search);
    const atPRINTpdf =qs && !!qs.PRINTpdf;
    const [printDialogOpen, setPrintDialogOpen] = useState(canURLprn&&atPRINTpdf);
    useEffect(() => {
        const afterPrint = async () => {
            setPrintDialogOpen(false);
        };
        window.addEventListener("afterprint", afterPrint);

        return () => {
            window.removeEventListener("afterprint", afterPrint);
        };
    });

    const [dimensions, setDimensions] = useState<{
        width: number;
        height: number;
    }>();
    //【仅仅是】屏幕显示的 ref ：打印预览这个无效的。
    const elementRef =useRef<HTMLDivElement | null>(null);

    useEffect(() => {
        const width: number = elementRef?.current?.clientWidth!;
        const height: number = elementRef?.current?.clientHeight!;
        if (width && height) {
            setDimensions({ width, height });
        } else {
            setDimensions({ width: FALLBACK_WIDTH, height: FALLBACK_HEIGHT });
        }
    }, []);

    const openPrintDialog = async () => {
        try {
            setPrintDialogOpen(true);
            await sleep(waitime);
            window.print();
        } catch (e) {
            // do nothing
        }
    };

    /*
    onClick={async () => {
                  // @ts-ignore
                  await ref.current.openPrintDialog();
              }}
    * */
    // useImperativeHandle(ref, () => ({     老版本的
    //     openPrintDialog,
    // } as any));

    const usedMarginTop = marginTop ?? MARGIN_TOP_DEFAULT;
    const usedMarginLeft = marginLeft ?? MARGIN_LEFT_DEFAULT;

    console.log("打印VAL", usedMarginTop + (dimensions?.height ?? 0), dimensions, usedMarginTop, usedMarginLeft,printWidth);

    async function onClick() {
        // setPrintDialogOpen(!printDialogOpen);
        await openPrintDialog();
    }
    const id = React.useId();
    //【最关键】width: printWidth ?? dimensions?.width, 需要自己配置打印纸张的大小A4 A3的宽度的+横屏 竖屏的。
    //打下的打印时刻的render是发生在scout.on('beforeprint', beforePrintHandler)前面了，随后原生打印预览环节仅仅做了复制没有再次render给打印输出的时机。导致没有触发useMedia('print')==true;
    //打印对话框关闭或者输出PDF之后的节点才会进入原先原生浏览器打印的运行过程的，但pdf内容始终没有触发useMedia('print')==true。
    //还有一个毛病：无法保留旧的状态数据或手动输入点击变动的内容！表格等数据初始化？只能加载后端的静态内容。
    //【毛病3】width必须事前做设置的数字。 不要按钮点击触发的话，改成URL内部特殊标记来指示打印context ?&PRINTpdf=1? 还是分叉机制？
    //【毛病4】有空白页。没法去掉；其他不打印的也占空间，需手动选择输出纸张数；
    const render= !printDialogOpen ? (
             <div ref={elementRef}>{node}</div>
       ) : (
        <>
            {createPortal(
                <div className="print-comp"
                     style={{
                         width: 718,
                         // width: printWidth ?? dimensions?.width,
                         // height: 90,  //dimensions?.height,
                         position: "absolute",
                         top: 0,
                         left: 0,
                         // marginTop: usedMarginTop,
                         // marginLeft: usedMarginLeft,
                     }}
                >
                    {node}
                </div> as React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | string | number | bigint | Iterable<React.ReactNode> | React.ReactPortal | boolean,
                document.body
            )}
            <style>
              {
                `* { visibility: hidden !important; } body { min-height: 0; height: ${
                          usedMarginTop + (dimensions?.height ?? 0)
                 }px; } .print-comp, .print-comp * { visibility: visible !important}`
              }
            </style>
        </>
    );

    return {
        id,
        buttonProps: {
            onClick : onClick,
            "aria-controls": id,
        },
        render: render,
    };
}


interface LandscapeOnOffProps extends React.HTMLAttributes<HTMLDivElement> {
    landscape?: boolean;
}
/**@Deprecated  测试用途的；
 * 预想的 A4 打印切换 横板竖版
 * 可惜！ 后面的会覆盖掉前面的； 所以尝试失败！
 * */
const LandscapeOnOff: React.FunctionComponent<LandscapeOnOffProps> =(
    {    landscape,  }
) => {
    function getStyleForRule(rule: string) {
        let style = document.createElement("style");
        style.innerHTML = rule;
        return style;
    }
    useInsertionEffect(() => {
        document.head.appendChild(getStyleForRule(`@page { size: A4${landscape? ' landscape':''}; }`));
    },[]);
    return null;
};


/**被动态网页的打印给折腾的：
 重新加载？打印敲定页数之后才会再一次render的。根本没机会计算ref.div最新宽度甚至用beforePrintHandler来setSuitableCls也没有机会提前调整。
 beforePrintHandler --》unmount this?重新加载
 react-to-print只会复制旧的组件页面也不能重新render的是甚至usemedia都无感知到打印。；
 只用css 不用JS做动态内容？；
 <style>
 {
 `:not(.print-comp) { visibility: hidden !important; } body { min-height: 0; height: ${
 usedMarginTop + (dimensions?.height ?? 0)
 }px; } .print-comp, .print-comp * { visibility: visible !important}`
 }
 </style>
 function sleep(time: number | undefined) {
     return new Promise(resolve =>
         setTimeout(resolve,time) )
 }
 async function pressWait() {
     let out = await sleep(9900);
     return out;
 }
* */
